package questions;

import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TransferQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

public class PrintInOrder {

    public static void main(String[] args) {
//        new TwoThread().print1();
//        new TwoThread().print2();
        new TwoThread().print3();
//        new MultiThread().print();
    }




}

class MultiThread{
    ReentrantLock lock = new ReentrantLock();
    Condition a =lock.newCondition();
    Condition b =lock.newCondition();
    Condition c =lock.newCondition();

    public void print() {
        new Thread(()->{
            lock.lock();
            try{
                for (;;) {
                    System.out.print(Thread.currentThread().getName());
                    b.signal();
                    a.await();
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }

        },"A").start();

        new Thread(()->{
            lock.lock();
            try{
                for (;;) {
                    System.out.print(Thread.currentThread().getName());
                    c.signal();
                    b.await();
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }

        },"B").start();

        new Thread(()->{
            lock.lock();
            try{
                for (;;) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(300);
                    a.signal();
                    c.await();
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"C").start();



    }


}

class TwoThread{
    char[] c1 = "1234567".toCharArray();
    char[] c2 = "abcdefg".toCharArray();
    Thread thread,thread1;
    Object lock = new Object();

    public void print3(){
        TransferQueue<Character> queue = new LinkedTransferQueue<>();

        new Thread(()->{
            try {
                for (char c :c1) {
                    System.out.println(queue.take());
                    queue.transfer(c);
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(()->{
            try {
                for (char c :c2) {
                    queue.transfer(c);
                    System.out.println(queue.take());
                }
            }catch (Exception e){
                e.printStackTrace();
            }

        }).start();

    }
    /**
     * wait/ notify
     */
    public void print2(){

        thread = new Thread(() -> {
            synchronized(lock) {
                for (char c : c2) {
                    System.out.print(c);
                    lock.notify();
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                lock.notify();
            }
        });
        thread1 = new Thread(() -> {
            synchronized (lock) {
                for (char c : c1) {
                    System.out.print(c);
                    lock.notify();
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                lock.notify();
            }
        });
        thread.start();
        thread1.start();
    }

    /**、
     * 方式1 LockSupport
     */
    public void print1(){

        thread = new Thread(() -> {
            for (char c :c2) {
                System.out.print(c);
                LockSupport.unpark(thread1);
                LockSupport.park();
            }
        });
        thread1 = new Thread(() -> {
            for (char c :c1) {
                LockSupport.park();
                System.out.print(c);
                LockSupport.unpark(thread);
            }
        });
        thread.start();
        thread1.start();

    }
}